﻿using System.Xml.Linq;
using Engine;
using System;
using Engine.Graphics;
using System.Collections.Generic;
using XmlUtilities;
using System.IO;
using Engine.Media;
using Game;

namespace MMap
{
	public static class MMapManager
	{
        static readonly Dictionary<Point2, Color> m_blockColors = [];
        public static void Initialize()
        {
            IEnumerator<XElement> enumerator = ContentManager.Get<XElement>("MMapColors").Elements().GetEnumerator();
            while (enumerator.MoveNext())
            {
                XElement xml = enumerator.Current;
                int index = XmlUtils.GetAttributeValue(xml, "Index", -1);
                int data = XmlUtils.GetAttributeValue(xml, "Data", -1);
                Color color = XmlUtils.GetAttributeValue(xml, "Color", Color.White);
                if (index > 0 && !m_blockColors.ContainsKey(new Point2(index, data)))
                    m_blockColors.Add(new Point2(index, data), color);
            }
        }
        public static Color GetBlockColor(int value, SubsystemTerrain subsystemTerrain, Point3? point)
        {
            Block block = BlocksManager.Blocks[Terrain.ExtractContents(value)];
            if (block is MagmaBlock)
                return new Color(222, 109, 20);
            if (block.GetEmittedLightAmount(value) > 0)
                return new Color(255, 250, 170);
            if (subsystemTerrain != null && point.HasValue)
            {
                if (block is IPaintableBlock paintableBlock)
                {
                    int? paintColor = paintableBlock.GetPaintColor(value);
                    if (paintColor.HasValue && paintColor.Value > 0)
                        return new Color(SubsystemPalette.GetColor(subsystemTerrain, paintColor), 255);
                }
                Color color = Color.White;
                if (block is WaterBlock)//水面颜色
                    color = BlockColorsMap.Water.Lookup(subsystemTerrain.Terrain, point.Value.X, point.Value.Y, point.Value.Z) * (168f / 255f);
                if (block is GrassBlock || block is GrassTrapBlock || block is GrassTrapBlock)//草方块&高草&草陷阱表面颜色
                    color = BlockColorsMap.Grass.Lookup(subsystemTerrain.Terrain, point.Value.X, point.Value.Y, point.Value.Z) * (165f / 255f);
                if (block is BirchLeavesBlock)//桦树叶颜色
                    color = BlockColorsMap.BirchLeaves.Lookup(subsystemTerrain.Terrain, point.Value.X, point.Value.Y, point.Value.Z) * (172f / 255f);
                if (block is MimosaLeavesBlock)//金合欢树叶颜色
                    color = BlockColorsMap.MimosaLeaves.Lookup(subsystemTerrain.Terrain, point.Value.X, point.Value.Y, point.Value.Z) * (172f / 255f);
                if (block is PoplarLeavesBlock)//杨树叶颜色
                    color = BlockColorsMap.PoplarLeaves.Lookup(subsystemTerrain.Terrain, point.Value.X, point.Value.Y, point.Value.Z) * (172f / 255f);
                if (block is OakLeavesBlock)//橡树叶颜色
                    color = BlockColorsMap.OakLeaves.Lookup(subsystemTerrain.Terrain, point.Value.X, point.Value.Y, point.Value.Z) * (172f / 255f);
                if (block is SpruceLeavesBlock)//杉树叶颜色
                    color = BlockColorsMap.SpruceLeaves.Lookup(subsystemTerrain.Terrain, point.Value.X, point.Value.Y, point.Value.Z) * (172f / 255f);
                if (block is TallSpruceLeavesBlock)//高大杉树叶颜色
                    color = BlockColorsMap.TallSpruceLeaves.Lookup(subsystemTerrain.Terrain, point.Value.X, point.Value.Y, point.Value.Z) * (172f / 255f);
                //if (GetSettingValue("显示更丰富的花草颜色"))
                {
                    if (block is IvyBlock)//藤蔓颜色
                        color = BlockColorsMap.Ivy.Lookup(subsystemTerrain.Terrain, point.Value.X, point.Value.Y, point.Value.Z) * (116f / 255f);
                    //if (block is KelpBlock)//海带颜色
                    //    color = BlockColorsMap.KelpColorsMap.Lookup(subsystemTerrain.Terrain, point.Value.X, point.Value.Y, point.Value.Z) * (159f / 255f);
                    //if (block is SeagrassBlock)//水草颜色
                    //    color = BlockColorsMap.SeagrassColorsMap.Lookup(subsystemTerrain.Terrain, point.Value.X, point.Value.Y, point.Value.Z) * (159f / 255f);
                    //if (block is RedFlowerBlock)//红花
                    //    color = new Color(224, 34, 20);
                    //if (block is WhiteFlowerBlock)//白花
                    //    color = new Color(213, 208, 131);
                    //if (block is PurpleFlowerBlock)//紫花
                    //    color = new Color(144, 68, 255);
                }
                //if (block is SoilBlock)//耕地颜色
                //    color = SoilBlock.GetHydration(Terrain.ExtractData(value)) ? new Color(180, 170, 150) : Color.White;?????
                if (color != Color.White)
                    return new Color(color, 255);
            }

            //精确匹配id
            int id = Terrain.ExtractContents(value), data = Terrain.ExtractData(value);
            if (m_blockColors.TryGetValue(new Point2(id, data), out Color color1))
                return color1;
            else if (m_blockColors.TryGetValue(new Point2(id, -1), out Color color0))
                return color0;
            else
            {//粗略匹配
                if (block.GetCategory(value) == BlocksManager.Blocks[SwitchBlock.Index].GetCategory(SwitchBlock.Index))
                    return new Color(85, 85, 85);//电路
                switch (block.GetSoundMaterialName(subsystemTerrain, value))
                {
                    case "Dirt":
                        return new Color(130, 101, 58);
                    case "Stone":
                        return new Color(148, 148, 148);
                    case "Sand":
                        return new Color(225, 206, 146);
                    case "Soft":
                        return new Color(161, 159, 151);
                    case "Snow":
                        return new Color(251, 255, 255);
                    case "Wood":
                        return new Color(110, 78, 43);
                    case "Plant":
                        return new Color(49, 88, 0);
                    case "Metal":
                        return new Color(212, 212, 212);
                    case "Glass":
                        return new Color(226, 231, 255);
                }
            }
            return Color.White;
        }

        public static float GetAngleByVector(Vector3 vector1, Vector3 vector2)
        {
            return MathUtils.Acos(Vector3.Dot(vector1, vector2) / vector1.Length() / vector2.Length());
        }
        public static int GetChunkTopHeight(TerrainChunk chunk, int x, int z)
        {
            return GetChunkTopHeight(chunk, x, z, false);
        }
        public static int GetChunkTopHeight(TerrainChunk chunk, int x, int z, bool allowTransBlock)
        {//allowTransBlock为false时液体或树叶直接返回为顶部
            int height = 253;
            Block block = BlocksManager.Blocks[chunk.GetCellContentsFast(x, height, z)];
            while (block is AirBlock || !allowTransBlock && !block.IsCollidable && block is not FluidBlock)
            {
                height--;
                block = BlocksManager.Blocks[chunk.GetCellContentsFast(x, height, z)];
            }
            return height;

        }

        public static bool LoadMapImage(string directory, string fileName, ref RenderTarget2D mapContent)
        {
            bool succuss = false;
            mapContent = new RenderTarget2D(MMapContent.MapSize.X, MMapContent.MapSize.Y, 1, ColorFormat.Rgba8888, DepthFormat.None);
            string path = Storage.CombinePaths(directory, fileName);
            try
            {
                RenderTarget2D previousTarget = Display.RenderTarget;
                using (Stream stream = Storage.OpenFile(path, OpenFileMode.Read))
                {
                    Image image = Image.Load(stream, ImageFileFormat.Png);
                    Texture2D texture2D = Texture2D.Load(image);
                    texture2D.Tag = image;
                    Display.RenderTarget = mapContent;
                    var primitivesRenderer2D = new PrimitivesRenderer2D();
                    TexturedBatch2D texturedBatch2D = primitivesRenderer2D.TexturedBatch(texture2D, useAlphaTest: false, layer: 0);
                    texturedBatch2D.QueueQuad(Vector2.Zero, new Vector2(texture2D.Width, texture2D.Height), 1f, Vector2.Zero, Vector2.One, Color.White);
                    primitivesRenderer2D.Flush();
                    succuss = true;
                }

                Display.RenderTarget = previousTarget;
            }
            catch (Exception ex)
            {
                Log.Warning(string.Format("Could not load a!! texture \"{0}\". Reason: {1}.", new object[2] { path, ex.Message }));
            }
            return succuss;
        }

        public static void SaveMapImage(string fileName, ref RenderTarget2D mapContent)
        {
            string directory = GameManager.WorldInfo.DirectoryName + "/MMap";
            Storage.CreateDirectory(directory);

            //var image = new Image(mapContent.Width, mapContent.Height);
            //mapContent.GetData(image.Pixels, 0, new Rectangle(0, 0, mapContent.Width, mapContent.Height));
            using Stream stream = Storage.OpenFile(Storage.CombinePaths(directory, fileName), OpenFileMode.CreateOrOpen);
            Image.Save(mapContent.GetData(new Rectangle(0, 0, mapContent.Width, mapContent.Height)), stream, ImageFileFormat.Png, saveAlpha: true);
			//Image.Save(image, stream, ImageFileFormat.Png, saveAlpha: true);

		}

	}
}
